#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/types.h>

#define KEYS_NUMBER 4

//设备类
static struct class *keys_class = NULL;
//子设备类
static struct class_device *keys_class_devs[KEYS_NUMBER] = {NULL};
//主设备号
int major = 0;
//GPF 配置寄存器地址
volatile unsigned long *gpfconfig = NULL;
//GPF 数据寄存器
volatile unsigned long *gpfdate = NULL;
//GPG 配置寄存器地址
volatile unsigned long *gpgconfig = NULL;
//GPG 数据寄存器
volatile unsigned long *gpgdate = NULL;

static int keys_open(struct inode *inode, struct file *file)
{
    int minor = MINOR(inode->i_rdev);

    //GPF 0,2 配置为输入模式
    *gpfconfig &= ~((0x03<<(0*2)) | (0x03<<(2*2)));
    //GPG 3,11 配置为输入模式
    *gpgconfig &= ~((0x03<<(3*2)) | (0x03<<(11*2)));

    return 0;
}

/*
 * buf 传入数据的缓存地址
 * count 传入数据的长度
 */
ssize_t keys_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
    unsigned char key_vers[4] = {0};
    int regval = 0;
    int minor = MINOR(file->f_dentry->d_inode->i_rdev);

    if(size < sizeof(key_vers))
        return -EINVAL;

    regval = *gpfdate;
    key_vers[0] = (regval & (0x01<<0)) ? 1 : 0;
    key_vers[1] = (regval & (0x01<<2)) ? 1 : 0;

    regval = *gpgdate;
    key_vers[2] = (regval & (0x01<<3)) ? 1 : 0;
    key_vers[3] = (regval & (0x01<<11)) ? 1 : 0;

    //将值传入用户空间
    copy_to_user(buf, key_vers, sizeof(key_vers));

    //获取应用程序传入的值
    //copy_from_user(&val, buf, 4);

    return sizeof(key_vers);
}

static struct file_operations keys_fops = {
    .owner = THIS_MODULE,
    .open = keys_open,
    .read = keys_read,
};

int keys_init(void)
{
    int i = 0;

    //注册驱动程序
    major = register_chrdev(0, "keys_dev", &keys_fops);

    //创建一个class
    keys_class = class_create(THIS_MODULE, "keys");
    if(IS_ERR(keys_class))
        return PTR_ERR(keys_class);

    //在类下面创建子设备
    for(i=0;i<KEYS_NUMBER;i++)
    {
        keys_class_devs[i] = class_device_create(keys_class, NULL, MKDEV(major, i), NULL, "key%d",i);
        if(unlikely(IS_ERR(keys_class_devs[i])))
            return PTR_ERR(keys_class_devs[i]);
    }

    //获取gpf config寄存器所对应的虚拟地址,一个寄存器32位 = 4字节，4个寄存器 size = 4 × 4 = 16
    gpfconfig = (volatile unsigned long *)ioremap(0x56000050,16);
    //获取gpf date寄存器所对应的虚拟地址,指针类型为4字节，所以 +1 为偏移4字节
    gpfdate = gpfconfig + 1;

    gpgconfig = (volatile unsigned long *)ioremap(0x56000060,16);
    gpgdate = gpgconfig + 1;

    return 0;
}

void keys_exit(void)
{
    int i = 0;

    //移除注册驱动程序
    unregister_chrdev(major, "keys_dev");

    //移除驱动程序类下面的设备
    for(i=0;i<KEYS_NUMBER;i++)
    {
        if(keys_class_devs[i] != NULL)
        {
            class_device_unregister(keys_class_devs[i]);
            keys_class_devs[i] = NULL;
        }
    }

    //移除驱动程序相关类
    class_destroy(keys_class);

    //取消地址映射
    iounmap(gpfconfig);
    iounmap(gpgconfig);
}

module_init(keys_init); //添加入口函数
module_exit(keys_exit); //删除入口函数

MODULE_LICENSE("GPL");
